﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using Microsoft.Win32;

using System.Data.Services.Client;

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using System.IO;

namespace CPlase
{
    public sealed class BlobUtils
    {
        public static bool SaveBlob(string BlobUrl, string Content, CloudBlobClient BlobClient = null)
        {
            try
            {
                if (BlobClient == null) BlobClient = Azure.GetBlobClient();
                var BlobRef = BlobClient.GetBlobReference(BlobUrl);
                BlobRef.UploadText(Content);
                return true;
            }
            catch { }
            return false;
        }

        public static bool SaveBlob(string BlobUrl, byte[] Content, CloudBlobClient BlobClient = null)
        {
            try
            {
                if (BlobClient == null) BlobClient = Azure.GetBlobClient();
                var BlobRef = BlobClient.GetBlobReference(BlobUrl);
                BlobRef.UploadByteArray(Content);
                return true;
            }
            catch { }
            return false;
        }

        public static bool SaveBlob(string BlobUrl, Stream Content, CloudBlobClient BlobClient = null)
        {
            try
            {
                if (BlobClient == null) BlobClient = Azure.GetBlobClient();
                var BlobRef = BlobClient.GetBlobReference(BlobUrl);
                BlobRef.UploadFromStream(Content);
                return true;
            }
            catch { }
            return false;
        }

        public static CloudBlob GetBlob(string BlobUrl, CloudBlobClient BlobClient = null)
        {
            var BlobPath = BlobUrl;
            if (BlobClient == null) BlobClient = Azure.GetBlobClient();
            var Blob = BlobClient.GetBlobReference(BlobPath);
            return Blob;
        }

        public static IEnumerable<IListBlobItem> GetDirectoryBlobs(string DirectoryURL, bool IncludeSubDirectories = true, CloudBlobClient BlobClient = null)
        {
            if (BlobClient == null) BlobClient = Azure.GetBlobClient();
            var BlobDirectory = BlobClient.GetBlobDirectoryReference(DirectoryURL);
            var Request = new BlobRequestOptions();
            Request.UseFlatBlobListing = IncludeSubDirectories;
            Request.BlobListingDetails = BlobListingDetails.None;
            return BlobDirectory.ListBlobs(Request);
        }

        public static bool ClearDirectory(string DirectoryURL, CloudBlobClient BlobClient = null)
        {
            if (BlobClient == null) BlobClient = Azure.GetBlobClient();
            var List = GetDirectoryBlobs(DirectoryURL, true, BlobClient);
            foreach (var Item in List)
            {
                string BlobURL = GetBlobStringURL(Item);
                var BlobRef = BlobClient.GetBlobReference(BlobURL);
                BlobRef.DeleteIfExists();
            }
            return true;
        }

        public static string GetBlobStringURL(IListBlobItem BlobItem)
        {
            string StringURL = BlobItem.Uri.AbsolutePath;
            StringURL = StringURL.Substring(StringURL.IndexOf(BlobItem.Container.Name + "/"));
            return StringURL;
        }

        public static bool CopyDirectory(string FromDirectoryURL, string ToDirectoryURL, CloudBlobClient BlobClient = null)
        {
            FromDirectoryURL = CleanUpDirectoryURL(FromDirectoryURL);
            ToDirectoryURL = CleanUpDirectoryURL(ToDirectoryURL);

            if (BlobClient == null) BlobClient = Azure.GetBlobClient();
            var List = GetDirectoryBlobs(FromDirectoryURL, true, BlobClient);
            foreach (var Item in List)
            {
                string BlobURL = GetBlobStringURL(Item);
                string PureName = BlobURL.Substring(FromDirectoryURL.Length);
                var NewBlobRef = BlobClient.GetBlobReference(ToDirectoryURL + PureName);
                var BlobRef = BlobClient.GetBlobReference(BlobURL);
                NewBlobRef.CopyFromBlob(BlobRef);
            }
            return false;
        }

        public static string CleanUpDirectoryURL(string DirectoryURL)
        {
            if (DirectoryURL.StartsWith("/")) DirectoryURL = DirectoryURL.Substring(1);
            if (DirectoryURL.EndsWith("/")) DirectoryURL = DirectoryURL.Substring(0, DirectoryURL.Length - 1);
            if (DirectoryURL.Trim() == "") throw new ArgumentException("Directory must be not empty");
            return DirectoryURL;
        }

        public static string GetBlobText(string BlobUrl, CloudBlobClient BlobClient = null)
        {
            try
            {
                var BlobPath = BlobUrl;
                var Blob = GetBlob(BlobPath, BlobClient);
                Blob.FetchAttributes();
                string BlobContent = "";
                if (Blob != null) BlobContent = Blob.DownloadText();
                if (BlobContent == null) BlobContent = "";
                return BlobContent;
            }
            catch { }
            return "";
        }

        public static byte[] GetBlobBinary(string BlobUrl, CloudBlobClient BlobClient = null)
        {
            byte[] BlobContent = new byte[1];
            BlobContent[0] = (byte)'\0';
            try
            {
                var BlobPath = BlobUrl;
                var Blob = GetBlob(BlobPath, BlobClient);
                Blob.FetchAttributes();
                if (Blob != null) { return Blob.DownloadByteArray(); }
            }
            catch { }
            return BlobContent;
        }

        public static Stream GetBlobStream(string BlobUrl, CloudBlobClient BlobClient = null)
        {
            MemoryStream BlobContent = new MemoryStream();
            try
            {
                var BlobPath = BlobUrl;
                var Blob = GetBlob(BlobPath, BlobClient);
                Blob.FetchAttributes();
                if (Blob != null) { Blob.DownloadToStream(BlobContent); BlobContent.Seek(0, SeekOrigin.Begin); }
            }
            catch { }
            return BlobContent;
        }

        public static bool DeleteBlob(string BlobPath, CloudBlobClient BlobClient = null)
        {
            try
            {
                if (BlobClient == null) BlobClient = Azure.GetBlobClient();
                var BlobRef = BlobClient.GetBlobReference(BlobPath);
                BlobRef.DeleteIfExists();
                return true;
            }
            catch { return false; }
        }

        public static bool DeleteBlobList(List<string> BlobPaths, CloudBlobClient BlobClient = null)
        {
            try
            {
                if (BlobClient == null) BlobClient = Azure.GetBlobClient();
                foreach (var BlobPath in BlobPaths)
                {
                    var BlobRef = BlobClient.GetBlobReference(BlobPath);
                    BlobRef.DeleteIfExists();
                }
                return true;
            }
            catch { return false; }
        }

        public static string Serialize(object Obj)
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(Obj);
        }

        public static string Serialize<T>(T Obj)
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(Obj);
        }

        public static T Deserialize<T>(string SerializedObject)
        {
            T Item;
            try
            {
                Item = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(SerializedObject);
            }
            catch
            {
                try
                {
                    Item = ZipDeserialize<T>(SerializedObject);
                }
                catch
                {
                    throw new Exception("deserialize problem");
                }
            }
            return Item;
        }

        public static string ZipSerialize(object Obj)
        {
            string JsonText = Newtonsoft.Json.JsonConvert.SerializeObject(Obj);
            return CPlase.Compression.Zip(JsonText);
        }

        public static string ZipSerialize<T>(T Obj)
        {
            string JsonText = Newtonsoft.Json.JsonConvert.SerializeObject(Obj);
            return CPlase.Compression.Zip(JsonText);
        }

        public static T ZipDeserialize<T>(string SerializedObject)
        {
            string UnzipedText = CPlase.Compression.UnZip(SerializedObject);
            return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(UnzipedText);
        }

        public static string GetSizeForHuman(long Size)
        {
            return FormatBytes(Size);
        }

        private static string FormatBytes(long bytes)
        {
            const int scale = 1024;
            string[] orders = new string[] { "GB", "MB", "KB", "Bytes" };
            long max = (long)Math.Pow(scale, orders.Length - 1);

            foreach (string order in orders)
            {
                if (bytes > max)
                    return string.Format("{0:##.##} {1}", decimal.Divide(bytes, max), order);

                max /= scale;
            }
            return "0 Bytes";
        }

        public static string GetMimeTypeFromExtension(string extension)
        {
            extension = extension.ToLowerInvariant();
            string contentType = "application/octet-stream";
            switch (extension)
            {
                case ".pdf":
                    contentType = "application/pdf";
                    break;
                case ".js":
                    contentType = "application/x-javascript";
                    break;
                case ".zip":
                    contentType = "application/x-zip-compressed";
                    break;
                case ".rar":
                    contentType = "application/x-rar-compressed";
                    break;
                case ".djv":
                    contentType = "image/vnd.djvu";
                    break;
                case ".djvu":
                    contentType = "image/vnd.djvu";
                    break;
                default:
                    RegistryKey key = Registry.ClassesRoot.OpenSubKey(extension);
                    try
                    {
                        if (key != null)
                        {
                            contentType = key.GetValue("Content Type").ToString();
                        }
                    }
                    catch
                    {

                    }
                    break;
            }
            return contentType;

        }

        public static MemoryStream MergeStreams(MemoryStream FirstStream, MemoryStream SecondStream)
        {
            int FirstStreamLength = FirstStream.ToArray().Length;
            int SecondStreamLength = SecondStream.ToArray().Length;

            MemoryStream MergeStream = new MemoryStream();
            MergeStream.Write(FirstStream.ToArray(), 0, FirstStreamLength);
            MergeStream.Write(SecondStream.ToArray(), 0, SecondStreamLength);

            return MergeStream;
        }

        public static string CombineUri(string First, string Second)
        {
            First = First.TrimEnd('/');
            Second = Second.TrimStart('/');
            return First + "/" + Second;
        }

        public static string GetUniqueFileName(CloudBlobDirectory BlobDirectory, string FileName)
        {
            //Remove illegal symbols
            string RegexSearch = new string(Path.GetInvalidFileNameChars());
            Regex R = new Regex(string.Format("[{0}]", Regex.Escape(RegexSearch)));
            FileName = R.Replace(FileName, "");
            FileName = FileName.Replace("#", "");
            FileName = FileName.Replace("%", "");
            FileName = FileName.Replace("&", "");
            FileName = FileName.Replace("^", "");
            FileName = FileName.Replace("+", "");

            string FileNameWithoutExtension = Path.GetFileNameWithoutExtension(FileName);

            if (String.IsNullOrWhiteSpace(FileNameWithoutExtension))
                FileNameWithoutExtension = "Untitled";

            string Extenstion = Path.GetExtension(FileName);

            CloudBlob Blob;
            string OutFileName = FileName;
            bool unique = false;
            int attempt = 0;
            while (!unique)
            {
                try
                {
                    Blob = BlobDirectory.GetBlobReference(OutFileName);
                    Blob.FetchAttributes();
                    OutFileName = FileNameWithoutExtension + attempt.ToString() + Extenstion;
                    attempt++;
                }
                catch
                {
                    unique = true;
                }
            }
            return OutFileName;
        }

    }

}